/*
创建文件、打开文件，写入文件
先获取文件大小，再依次按一定大小循环读取文件。当成功读取的数据大小等于文件总大小时，读取结束。

CreateFile、ReadFile、WriteFile、CloseHandle函数
SetFilePointer函数
GetFileSizeEx函数
_tprintf、_tcslen函数
TEXT宏
*/
#include <windows.h>
#include <tchar.h>

void SaveFileData(PCTSTR szFileName, LPCVOID szFileData, DWORD dwNumberOfBytesToWrite);
int ReadDataHex(PCTSTR szFileName);

int WINAPI WinMain(HINSTANCE hHinstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    // 待写入的字符串
    PCTSTR szFileData = TEXT("满目山河空念远，落花风雨更伤春，不如怜取眼前人。");
    PCTSTR szFileName = TEXT("d:\\test\\1.txt");

    // 第3个参数不能写sizeof(szFileData)
    // sizeof(szFileData)，获取字符指针的长度（64位，8字节）
    // _tcslen(szFileData) * sizeof(TCHAR)，获取字符串长度
    SaveFileData(szFileName, szFileData, _tcslen(szFileData) * sizeof(TCHAR));
    // 读取
    ReadDataHex(szFileName);

    return 0;
}

/* 写入 */
void SaveFileData(PCTSTR szFileName, LPCVOID szFileData, DWORD dwNumberOfBytesToWrite)
{
    // 文件句柄
    HANDLE hFileWrite;
    // 成功写入的数据大小
    DWORD dwNumberOfBytesWritten;

    // 打开文件
    hFileWrite = CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    // 判断是否打开成功
    if (hFileWrite==INVALID_HANDLE_VALUE) {
        _tprintf(TEXT("打开 %s 文件失败。错误代码是：%lu。\n"), szFileName, GetLastError());
    } else{
        // 设置文件指针到文件末
        SetFilePointer(hFileWrite, 0, 0, FILE_END);
        // 写入文件
        if (!WriteFile(hFileWrite, szFileData, dwNumberOfBytesToWrite, &dwNumberOfBytesWritten, NULL)) {
            _tprintf(TEXT("写入 %s 文件失败。错误代码是：%lu。\n"), szFileName, GetLastError());
        } else {
            _tprintf(TEXT("写入 %s 文件成功。写入的字节总数：%lu。\n"), szFileName, dwNumberOfBytesWritten);
        }
    }
    CloseHandle(hFileWrite);
}

/* 读取 */
int ReadDataHex(PCTSTR szFileName)
{
    // 文件句柄
    HANDLE hFileRead;
    // 文件大小
    LARGE_INTEGER liFileSize;
    // 每次读取文件的数据缓存
    BYTE lpBuffer[32];
    // 每次成功读取文件的大小
    DWORD dwNumberOfBytesRead;
    // 累加计算已经读取数据的大小
    LONGLONG llTotalRead = 0;

    // 打开文件
    hFileRead = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    // 判断是否打开成功
    if (hFileRead == INVALID_HANDLE_VALUE) {
        _tprintf(TEXT("打开 %s 文件失败。错误代码是：%lu。\n"), szFileName, GetLastError());
        return -1;
    }

    // 获取文件大小
    if (!GetFileSizeEx(hFileRead, &liFileSize)) {
        _tprintf(TEXT("获取 %s 文件大小失败。错误代码是：%lu。\n"), szFileName, GetLastError());
        return -2;
    } else {
        _tprintf(TEXT("\n\n文件 %s 大小：%I64d。\n"), szFileName, liFileSize.QuadPart);
    }

    // 循环读取并打印文件内容
    while (TRUE) {
        if (!ReadFile(hFileRead, lpBuffer, 32, &dwNumberOfBytesRead, NULL)) {
            _tprintf(TEXT("文件 %s 读取出错。错误代码是：%lu。\n"), szFileName, GetLastError());
            break;
        }
        _tprintf(TEXT("读取了 %lu 字节。文件内容是：\n"), dwNumberOfBytesRead);

        for (int i=0; i<dwNumberOfBytesRead; i++) {
            _tprintf(TEXT("0x%x "), lpBuffer[i]);
        }
        _tprintf(TEXT("\n"));

        llTotalRead += dwNumberOfBytesRead; 
        if (llTotalRead == liFileSize.QuadPart) {
            _tprintf(TEXT("读取文件结束。\n\n"));
            break;
        }
    }
    CloseHandle(hFileRead);
    return 0;
}